import { ModsInstance } from "@/func/createMod";
import { BaseIO } from "./baseIO";
import { getModeFuncRet, Result, RetResult } from "../tools/modHelper";

// 媒介状态
type MediaStatus =
	| "PRESENT"
	| "NOTPRESENT"
	| "JAMMED"
	| "NOTSUPP"
	| "UNKNOWN"
	| "ENTERING"
	| "RETRACTED";

// 打印机状态
type DeviceStatus =
	| "HEALTHY"
	| "HWERROR"
	| "NODEVICE"
	| "OFFLINE"
	| "POWEROFF"
	| "USERERROR"
	| "BUSY"
	| "FRAUDATTEMPT"
	| "POTENTIALFRAUD";

// 纸供给状态
type PaperStatus = "FULL" | "LOW" | "OUT" | "NOTSUPP" | "UNKNOWN" | "JAMMED";

// 打印机中盖章墨水的状态（如果可能）
type InkStatus = "InkStatus" | "FULL" | "LOW" | "OUT" | "NOTSUPP";

export interface PrrState {
	StMediaStatus: MediaStatus;
	StDeviceStatus: DeviceStatus;
	StPaperStatus: PaperStatus;
	StInkStatus: InkStatus;
}
export interface PrrCapability {}

type PrintRet = "PrintComplete" | "DeviceError" | "FatalError";

type PrintRawDataRet =
	| "PrintComplete"
	| "InvalidPrintData"
	| "DeviceError"
	| "FatalError";

type EjectRet =
	| "PrintEjected"
	| "PrintTaken"
	| "Timeout"
	| "DeviceError"
	| "FatalError";

type ResetRet = "ResetComplete" | "DeviceError" | "FatalError";

type RetractRet = "PrintRetracted" | "DeviceError" | "FatalError";

type CancelWaitForPrintTakenRet =
	| "PrintEjected"
	| "PrintTaken"
	| "Timeout"
	| "DeviceError"
	| "FatalError"
	| "WaitCancelled";

export interface ExtendedPrintParams {
	FormName: string;
	FieldValues: string;
	MediaName: string;
	Alignment: string;
	XOffset: number;
	YOffset: number;
	MediaAction: string;
}

export class Prr extends BaseIO<PrrState, PrrCapability> {
	constructor(modName: keyof ModsInstance, mod: any) {
		super(modName, mod);
	}

	ExtendedPrint(Params: ExtendedPrintParams) {
		Trace(EC_INFO, `-->Prr:ExtendedPrint`);
		this.setCurrentMethod("ExtendedPrint");
		this.removeMethodBindEvt("ExtendedPrint");
		return new Promise<RetResult<PrintRet>>((resolve, reject) => {
			const PrintComplete = (...args: any[]) => {
				Trace(EC_INFO, `<--${this.modName}:ExtendedPrint PrintComplete`);
				resolve(getModeFuncRet(this.modName, "PrintComplete", args));
			};
			const DeviceError = (...args: any[]) => {
				Trace(EC_INFO, `<--${this.modName}:ExtendedPrint DeviceError`);
				resolve(getModeFuncRet(this.modName, "DeviceError", args));
			};
			const FatalError = (...args: any[]) => {
				Trace(EC_INFO, `<--${this.modName}:ExtendedPrint FatalError`);
				resolve(getModeFuncRet(this.modName, "FatalError", args));
			};

			this.add("PrintComplete", PrintComplete);
			this.add("DeviceError", DeviceError);
			this.add("FatalError", FatalError);

			this.mod.ExtendedPrint(
				Params.FormName,
				Params.FieldValues,
				Params.MediaName,
				Params.Alignment,
				Params.XOffset,
				Params.YOffset,
				Params.MediaAction,
				(ret: string) => {
					console.log(Params);
					if (parseInt(ret) != 0) {
						Trace(EC_INFO, `<--${this.modName}:ExtendedPrint ret=` + ret);
						resolve(getModeFuncRet(this.modName, "FatalError"));
					}
				}
			);
		}).then((value) => {
			this.removeMethodBindEvt("ExtendedPrint");
			return value;
		});
	}

	/**
	 * 凭条切纸
	 * @param {number} iTimeout 超时时间
	 * @returns {Promise<json>} - {mod:this.name, ret: '', param: arg}
	 * @return {String} return.mod 模块名
	 * @return {String} return.ret 事件 <br> PrintEjected - 凭条被弹出 <br> PrintTaken - 凭条被取走 <br> Timeout - 超时 <br> FatalError - 失败 <br> DeviceError - 设备故障 <br>
	 * @return {Array} return.param - 事件参数 无
	 */
	Eject(iTimesout: number) {
		Trace(EC_INFO, `-->Prr:Eject`);
		this.setCurrentMethod("Eject");
		this.removeMethodBindEvt("Eject");
		return new Promise<RetResult<EjectRet>>((resolve, reject) => {
			const PrintEjected = (...args: any[]) => {
				Trace(EC_INFO, `<--${this.modName}:eject PrintEjected`);
				resolve(getModeFuncRet(this.modName, "PrintEjected", args));
			};
			const PrintTaken = (...args: any[]) => {
				Trace(EC_INFO, `<--${this.modName}:eject PrintTaken`);
				resolve(getModeFuncRet(this.modName, "PrintTaken", args));
			};
			const Timeout = (...args: any[]) => {
				Trace(EC_INFO, `<--${this.modName}:eject Timeout`);
				resolve(getModeFuncRet(this.modName, "Timeout", args));
			};
			const DeviceError = (...args: any[]) => {
				Trace(EC_INFO, `<--${this.modName}:eject DeviceError`);
				resolve(getModeFuncRet(this.modName, "DeviceError", args));
			};
			const FatalError = (...args: any[]) => {
				Trace(EC_INFO, `<--${this.modName}:eject FatalError`);
				resolve(getModeFuncRet(this.modName, "FatalError", args));
			};

			this.add("PrintEjected", PrintEjected);
			this.add("PrintTaken", PrintTaken);
			this.add("Timeout", Timeout);
			this.add("DeviceError", DeviceError);
			this.add("FatalError", FatalError);

			this.mod.Eject(iTimesout, (ret: string) => {
				if (parseInt(ret) != 0) {
					Trace(EC_INFO, `<--${this.modName}:eject ret=` + ret);
					resolve(getModeFuncRet(this.modName, "FatalError"));
				}
			});
		}).then((value) => {
			this.removeMethodBindEvt("Eject");
			return value;
		});
	}

	/**
	 * 原始打印
	 * @param {string} strData 打印内容
	 * @returns {Promise<json>} - {mod:this.name, ret: '', param: arg}
	 * @return {String} return.mod 模块名
	 * @return {String} return.ret 事件 <br> PrintComplete - 打印完成 <br> InvalidPrintData - 非法数据 <br> FatalError - 失败 <br> DeviceError - 设备故障 <br>
	 * @return {String} return.ret 返回值   各域值内容的json对象
	 */
	PrintRawData(strData: string) {
		Trace(EC_INFO, `-->Prr:PrintRawData`);
		this.setCurrentMethod("PrintRawData");
		this.removeMethodBindEvt("PrintRawData");
		return new Promise<RetResult<PrintRawDataRet>>((resolve, reject) => {
			const PrintComplete = (...args: []) => {
				// this.RemoveAll();
				Trace(EC_INFO, `<--${this.modName}:printRawData PrintEjected`);
				resolve(getModeFuncRet(this.modName, "PrintComplete", args));
			};
			const InvalidPrintData = (...args: []) => {
				// this.RemoveAll();
				Trace(EC_INFO, `<--${this.modName}:printRawData PrintEjected`);
				resolve(getModeFuncRet(this.modName, "InvalidPrintData", args));
			};
			const DeviceError = (...args: []) => {
				// this.RemoveAll();
				Trace(EC_INFO, `<--${this.modName}:printRawData PrintEjected`);
				resolve(getModeFuncRet(this.modName, "DeviceError", args));
			};
			const FatalError = (...args: []) => {
				// this.RemoveAll();
				Trace(EC_INFO, `<--${this.modName}:printRawData PrintEjected`);
				resolve(getModeFuncRet(this.modName, "FatalError", args));
			};

			this.add("PrintComplete", PrintComplete);
			this.add("DeviceError", DeviceError);
			this.add("InvalidPrintData", InvalidPrintData);
			this.add("FatalError", FatalError);

			this.mod.PrintRawData(strData, (ret: string) => {
				if (parseInt(ret) != 0) {
					Trace(EC_INFO, "-->PrintRawData ret=" + ret);
					resolve(getModeFuncRet(this.modName, "FatalError"));
				}
			});
		}).then((value) => {
			this.removeMethodBindEvt("PrintRawData");
			return value;
		});
	}

	/**
	 * 设备复位
	 * @param {string} ResetAction 复位动作：取值如下"EJECT" "CUT" "RETRACT"
	 * @param {number} RetractBinNumber 回收到中间栈盒的编号
	 * @returns {Promise<json>} - {mod:this.name, ret: '', param: arg}
	 * @return {String} return.mod 模块名
	 * @return {String} return.ret 事件 <br> ResetComplete - 复位完成 <br> FatalError - 失败 <br> DeviceError - 设备故障 <br> Timeout - 超时 <br>
	 * @return {Array} return.param - 事件参数 无
	 */
	Reset(ResetAction: string, RetractBinNumber?: number) {
		Trace(EC_INFO, `-->Prr:Reset`);
		this.setCurrentMethod("Reset");
		this.removeMethodBindEvt("Reset");
		return new Promise<RetResult<ResetRet>>((resolve, reject) => {
			const ResetComplete = (...args: any[]) => {
				Trace(EC_INFO, `<--${this.modName}:reset ResetComplete`);
				resolve(getModeFuncRet(this.modName, "ResetComplete", args));
			};
			const FatalError = (...args: any[]) => {
				Trace(EC_INFO, `<--${this.modName}:reset FatalError`);
				resolve(getModeFuncRet(this.modName, "FatalError", args));
			};
			const DeviceError = (...args: any[]) => {
				Trace(EC_INFO, `<--${this.modName}:reset DeviceError`);
				resolve(getModeFuncRet(this.modName, "DeviceError", args));
			};

			this.add("ResetComplete", ResetComplete);
			this.add("DeviceError", DeviceError);
			this.add("FatalError", FatalError);

			this.mod.Reset(ResetAction, RetractBinNumber, (ret: string) => {
				if (parseInt(ret) != 0) {
					Trace(EC_INFO, "-->Reset ret=" + ret);
					resolve(getModeFuncRet(this.modName, "FatalError"));
				}
			});
		}).then((value) => {
			this.removeMethodBindEvt("Reset");
			return value;
		});
	}

	/**
	 * 回收凭条
	 * @param {number} BinNumber 回收到中间栈盒的编号
	 * @returns {Promise<json>} - {mod:this.name, ret: '', param: arg}
	 * @return {String} return.mod 模块名
	 * @return {String} return.ret 事件 <br> PrintRetracted - 回收完成 <br> FatalError - 失败 <br> DeviceError - 设备故障 <br>
	 * @return {Array} return.param - 事件参数 无
	 */
	Retract(BinNumber: number) {
		Trace(EC_INFO, `-->Prr:Retract`);
		this.setCurrentMethod("Retract");
		this.removeMethodBindEvt("Retract");
		return new Promise<RetResult<RetractRet>>((resolve, reject) => {
			const PrintRetracted = (...args: any[]) => {
				Trace(EC_INFO, `<--${this.modName}:Retract PrintRetracted`);
				resolve(getModeFuncRet(this.modName, "PrintRetracted", args));
			};
			const FatalError = (...args: any[]) => {
				Trace(EC_INFO, `<--${this.modName}:Retract FatalError`);
				resolve(getModeFuncRet(this.modName, "FatalError", args));
			};
			const DeviceError = (...args: any[]) => {
				Trace(EC_INFO, `<--${this.modName}:Retract DeviceError`);
				resolve(getModeFuncRet(this.modName, "DeviceError", args));
			};

			this.add("PrintRetracted", PrintRetracted);
			this.add("DeviceError", DeviceError);
			this.add("FatalError", FatalError);

			this.mod.Retract(BinNumber, (ret: string) => {
				if (parseInt(ret) != 0) {
					Trace(EC_INFO, "-->Retract ret=" + ret);
					resolve(getModeFuncRet(this.modName, "FatalError"));
				}
			});
		}).then((value) => {
			this.removeMethodBindEvt("Retract");
			return value;
		});
	}

	/**
	 * 取消等待凭条取走的事件
	 * @param {number} iTimeout 超时时间
	 * @returns {Promise<json>} - {mod:this.name, ret: '', param: arg}
	 * @return {String} return.mod 模块名
	 * @return {String} return.ret 事件 <br> PrintEjected - 凭条被弹出 <br> PrintTaken - 凭条被取走 <br> Timeout - 超时 <br> FatalError - 失败 <br> DeviceError - 设备故障 <br> WaitCancelled - 取消成功 <br>
	 * @return {Array} return.param - 事件参数 无
	 */
	CancelWaitForPrintTaken(timeout: number) {
		Trace(EC_INFO, `-->Prr:CancelWaitForPrintTaken`);
		this.setCurrentMethod("CancelWaitForPrintTaken");
		this.removeMethodBindEvt("CancelWaitForPrintTaken");
		return new Promise<RetResult<CancelWaitForPrintTakenRet>>(
			(resolve, reject) => {
				const PrintEjected = (...args: any[]) => {
					Trace(
						EC_INFO,
						`<--${this.modName}:CancelWaitForPrintTaken PrintEjected`
					);
					resolve(getModeFuncRet(this.modName, "PrintEjected", args));
				};
				const PrintTaken = (...args: any[]) => {
					Trace(
						EC_INFO,
						`<--${this.modName}:CancelWaitForPrintTaken PrintTaken`
					);
					resolve(getModeFuncRet(this.modName, "PrintTaken", args));
				};
				const Timeout = (...args: any[]) => {
					Trace(EC_INFO, `<--${this.modName}:CancelWaitForPrintTaken Timeout`);
					resolve(getModeFuncRet(this.modName, "Timeout", args));
				};
				const DeviceError = (...args: any[]) => {
					Trace(
						EC_INFO,
						`<--${this.modName}:CancelWaitForPrintTaken DeviceError`
					);
					resolve(getModeFuncRet(this.modName, "DeviceError", args));
				};
				const FatalError = (...args: any[]) => {
					Trace(
						EC_INFO,
						`<--${this.modName}:CancelWaitForPrintTaken FatalError`
					);
					resolve(getModeFuncRet(this.modName, "FatalError", args));
				};
				const WaitCancelled = (...args: any[]) => {
					Trace(
						EC_INFO,
						`<--${this.modName}:CancelWaitForPrintTaken WaitCancelled`
					);
					resolve(getModeFuncRet(this.modName, "WaitCancelled", args));
				};

				this.add("PrintEjected", PrintEjected);
				this.add("PrintTaken", PrintTaken);
				this.add("Timeout", Timeout);
				this.add("DeviceError", DeviceError);
				this.add("FatalError", FatalError);
				this.add("WaitCancelled", WaitCancelled);

				this.mod.CancelWaitForPrintTaken(timeout, (ret: string) => {
					if (parseInt(ret) != 0) {
						Trace(EC_INFO, "-->CancelWaitForPrintTaken ret=" + ret);
						resolve(getModeFuncRet(this.modName, "FatalError"));
					}
				});
			}
		).then((value) => {
			this.removeMethodBindEvt("CancelWaitForPrintTaken");
			return value;
		});
	}
}
